package basis.ea;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.hamcrest.internal.ArrayIterator;

public class Datenfeld
{
  private String feld = "";
  private String trennzeichen = ",";
  
  
  public Datenfeld (String feldwert) 
  {
    feld = feldwert;
  }
  
  
  public Datenfeld (Object objekt, Exportdatei ed) throws IOException
  {
    /* Verarbeitung von iterierbaren Listen (z.B. ArrayList)            */
    if (objekt instanceof Iterable)
    {
      feld = iterableZuText (objekt);
    }
    /* Verarbeitung von Schluessel-Wert-Listen (z.B. HashMap)           */
    if (objekt instanceof Map)
    {
      feld = mapZuText (objekt);
    }
    /* Verarbeitung von Arrays                                          */
    if (objekt.getClass ().isArray ())
    {
      feld = arrayZuText (objekt);
    }
    /* Verarbeitung von primitiven Datentypen                           */
    if (istPrimitiverTyp (objekt.getClass ()))
    {
      feld = datenfelderZuText (objekt);
    }
    /* Verarbeitung von individuellen Objekten                          */
    if (Datenfeld.istIndividualObjekt (objekt))
    {
      /* Dateiname und Inhalt in dieser Datei speichern (Rekursion)     */
      feld = "{" + objekt.getClass ().getSimpleName () + "}";
      new Exportdatei (objekt, ed);
    }
  }

  
  public String toString ()
  {
    return feld;
  }
  
  
  /**
   * Gibt primitive Datentypen als formatierten Text zurueck 
   */
  private String datenfelderZuText (Object objekt)
  {
    String ausgabe = "";
    
    if (istPrimitiverTyp (objekt.getClass ()))
    {
      ausgabe = objekt.toString ();
    }
    return ausgabe;
  }
  
  
  /**
   * Prueft ob eine Klasse ein primitiver Typ von Java ist.
   * Inklusive String und der Beruecksichtigung von Auto-Boxing!
   */
  protected static boolean istPrimitiverTyp (Class<?> klasse)
  {
    return klasse.equals (Boolean.class)
        || klasse.equals (Integer.class)
        || klasse.equals (Character.class)
        || klasse.equals (Byte.class) 
        || klasse.equals (Short.class)
        || klasse.equals (Double.class) 
        || klasse.equals (Long.class)
        || klasse.equals (Float.class) 
        || klasse.equals (String.class);
  }
  
  
  /**
   * Gibt Arrays als formatierten Text zurueck. Beispiel: [1;2;3]
   */
  private String arrayZuText (Object objekt)
  {
    String ausgabe = "[";
    ArrayIterator ai = new ArrayIterator (objekt);
    
    while (ai.hasNext ())        
    {
      ausgabe += datenfelderZuText (ai.next ());
      
      if (ai.hasNext ())
      {
        ausgabe += trennzeichen;        /* Zwischentrennzeichen         */      
      }
    }
    return ausgabe + "]";
  }
  
  /**
   * Gibt iterierbare Collections als formatierten Text zurueck
   */
  private String iterableZuText (Object objekt)
  {
    Method method;
    Iterator<?> ergebnisliste;
    String ausgabe = "[";
    
    try
    {
      method = objekt.getClass ().getMethod ("iterator");
      ergebnisliste = (Iterator<?>) method.invoke (objekt);
      while (ergebnisliste.hasNext ())
      {
        ausgabe += datenfelderZuText (ergebnisliste.next ());
        if (ergebnisliste.hasNext ())
        {
          ausgabe += trennzeichen;      /* Zwischentrennzeichen         */
        }
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    return ausgabe + "]";
  }
  
  
  /**
   * Gibt Maps (Schluessel-Wert) als formatierten Text zurueck
   */
  private String mapZuText (Object objekt)
  {
    Method method;
    Set<?> ergebnis;
    Iterator<?> ergebnisliste;
    Map.Entry<?, ?> eintrag;
    String ausgabe = "[";
    
    try
    {
      method = objekt.getClass ().getMethod ("entrySet");
      ergebnis = (Set<?>) method.invoke (objekt);
      ergebnisliste = ergebnis.iterator ();
      while (ergebnisliste.hasNext ())  
      {
        eintrag = (Map.Entry<?, ?>) ergebnisliste.next ();
        ausgabe += datenfelderZuText ("(" + 
            eintrag.getKey () + trennzeichen + 
            eintrag.getValue () + ")");
        if (ergebnisliste.hasNext ())
        {
          ausgabe += trennzeichen;      /* Zwischentrennzeichen         */
        }
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    return ausgabe + "]";
  }
  
  
  /**
   * Prueft ob ein Objekt keine Liste und kein primitver Datentyp ist
   */
  protected static boolean istIndividualObjekt (Object objekt)
  {
    if ((objekt instanceof Iterable)     
        || (objekt instanceof Map)          
        || (objekt.getClass ().isArray ())   
        || (istPrimitiverTyp (objekt.getClass ())))
    {
      return false;
    }
    else
    {
      return true;
    }
  }
}
